package com.nexgo.payment.action.inputpin;

import android.support.annotation.NonNull;

import com.nexgo.common.ByteUtils;
import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.device.pinpad.OnPinPadInputListener;
import com.nexgo.oaf.apiv3.device.pinpad.PinAlgorithmModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.PinPad;
import com.nexgo.oaf.apiv3.device.pinpad.PinPadKeyCode;
import com.nexgo.payment.aop.annotation.RunOnMainThread;
import com.nexgo.payment.api.ApiDeviceEngine;
import com.nexgo.payment.constrant.PreferencesConstants;
import com.nexgo.payment.constrant.SysConstant;
import com.nexgo.payment.databases.DataSource;
import com.nexgo.payment.entity.TransData;
import com.nexgo.payment.util.StringUtils;
import com.nexgo.sound.SoundManager;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * 输入密码
 * <p>
 * Created by xiaox on 2017/7/6.
 */
public class InputPinPresenter implements InputPinContract.Presenter {
    private final InputPinContract.View mView;
    private final DataSource mRepository;
    private final TransData mTransData;
    private final SoundManager mSoundManager;
    private boolean mIsOnlinePin;
    private final PinPad mSdkPinPad;
    private boolean mIsRunning;
    private boolean mIsInputPinComplete;
    private boolean mIsFirstTime = true;

    public InputPinPresenter(@NonNull InputPinContract.View view, @NonNull DataSource repository, @NonNull TransData transData, boolean isOnlinePin) {
        this.mView = checkNotNull(view);
        this.mRepository = checkNotNull(repository);
        this.mTransData = checkNotNull(transData);
        mIsOnlinePin = isOnlinePin;
        mSdkPinPad = ApiDeviceEngine.getInstance().getPinPad();
        view.setPresenter(this);
        mSoundManager = new SoundManager();
    }

    @Override
    public void start() {
        if (!mIsInputPinComplete && mIsFirstTime) {
            mIsFirstTime = false;
            mSoundManager.play(SoundManager.Type.ENTER_PIN);
            startInputPin();
        }
    }

    @Override
    public void pause() {

    }

    @Override
    public void destroy() {
        mSoundManager.stop();
        if (mSdkPinPad.isInputting() && mIsRunning) {
            mSdkPinPad.cancelInput();
        }
    }

    /**
     * 开始初始化密码键盘
     */
    private void startInputPin() {
        int[] pinLimit = new int[]{0, 4, 5, 6, 7, 8, 9, 10, 11, 12};
        byte[] pan = new byte[16];
//        交行特殊，但APIV3 默认按银联标准的来，特殊处理
        byte[] block = mTransData.getPan().getBytes();
        System.arraycopy(block, 0, pan, 0, 16);
        int mKeyIdx = Integer.parseInt(StringUtils.firstNonEmpty(mRepository.getParamValue(PreferencesConstants.MASTER_KEY_INDEX), "0"));
        int ret;
        if (mIsOnlinePin) {
            ret = mSdkPinPad.inputOnlinePin(pinLimit, SysConstant.TIME_OUT_60, pan, mKeyIdx, PinAlgorithmModeEnum.ISO9564FMT1, mPinPadInputListener);
        } else {
            ret = mSdkPinPad.inputOfflinePin(pinLimit, SysConstant.TIME_OUT_60, mPinPadInputListener);
        }
        if (ret == SdkResult.Success) {
            mIsRunning = true;
            postMainThread(() -> mView.showCountTime(SysConstant.TIME_OUT_60));
        } else {
            postMainThread(() -> mView.showPinError());
        }
    }

    /**
     * 输入密码结果监听
     */
    private OnPinPadInputListener mPinPadInputListener = new OnPinPadInputListener() {
        @Override
        public void onInputResult(int retCode, byte[] data) {
            mIsInputPinComplete = true;
            mIsRunning = false;
            switch (retCode) {
                case SdkResult.Success:
                    postMainThread(() -> mView.showPinConfirm(data));
                    break;
                case SdkResult.PinPad_No_Pin_Input:
                    //强制输入密码，不可返回
                    if (mTransData.isForcePin()){
                        postMainThread(() -> mView.showForcePin());
                        //重新初始化密码键盘
                        startInputPin();
                        return;
                    }
                    postMainThread(() -> mView.showPinConfirm(null));
                    break;
                case SdkResult.PinPad_Input_Timeout:
                    postMainThread(() -> mView.showPinTimeout());
                    break;
                case SdkResult.PinPad_Input_Cancel:
                    postMainThread(() -> mView.showPinCancel());
                    break;
                default:
                    postMainThread(() -> mView.showPinError());
                    break;
            }
        }

        @Override
        public void onSendKey(byte keyCode) {
            if (keyCode == PinPadKeyCode.KEYCODE_CLEAR) {
                postMainThread(() -> mView.showPinClear());
            } else {
                postMainThread(() -> mView.showPinMask());
            }
        }
    };

    @RunOnMainThread
    private void postMainThread(Runnable runnable) {
        if (mView.isActive()) {
            runnable.run();
        }
    }
}
